/*
 * StartApplication.java
 *
 * Created on Nov 22, 2009 12:23:27 PM;
 */

package edu.utx.timesynctest;

import com.sun.spot.peripheral.Spot;
import com.sun.spot.peripheral.IAT91_TC;
import com.sun.spot.peripheral.TimerCounterBits;
import com.sun.spot.peripheral.ISleepManager;
import com.sun.spot.sensorboard.EDemoBoard;
import com.sun.spot.sensorboard.peripheral.ISwitch;
import com.sun.spot.sensorboard.peripheral.ITriColorLED;
import com.sun.spot.peripheral.radio.RadioFactory;
import com.sun.spot.peripheral.radio.IRadioPolicyManager;
import com.sun.spot.io.j2me.radiostream.*;
import com.sun.spot.io.j2me.radiogram.*;
import com.sun.spot.util.*;
import com.sun.squawk.VM;

import java.io.*;
import javax.microedition.io.*;
import javax.microedition.midlet.MIDlet;
import javax.microedition.midlet.MIDletStateChangeException;


import edu.utx.spot.timesync.ChainedAT91TimerCounterSyncClock;
import edu.utx.spot.timesync.AT91TimerCounterSyncClock;
import edu.utx.spot.timesync.SystemTimerSyncClock;
import edu.utx.spot.timesync.ISyncClock;
import edu.utx.spot.timesync.protocol.TimeServer;
import edu.utx.spot.timesync.protocol.TimeClient;
import edu.utx.spot.timesync.protocol.IClockController;
import edu.utx.spot.timesync.protocol.NullClockController;
import edu.utx.spot.timesync.protocol.PIDClockController;

import com.sun.spot.peripheral.IAT91_AIC;

/**
 * The startApp method of this class is called by the VM to start the
 * application.
 * 
 * The manifest specifies this class as MIDlet-1, which means it will
 * be selected for execution.
 */
public class StartApplication extends MIDlet {

    private ITriColorLED [] leds = EDemoBoard.getInstance().getLEDs();

    protected void startApp() throws MIDletStateChangeException {
        System.out.println("Time synchronization test");
        new BootloaderListener().start();   // monitor the USB (if connected) and recognize commands from host

        final long serverAddr = IEEEAddress.toLong("0014.4F01.0000.53CB");
        long ourAddr = RadioFactory.getRadioPolicyManager().getIEEEAddress();
        System.out.println("Our radio address = " + IEEEAddress.toDottedHex(ourAddr));

        IRadioPolicyManager rpm = Spot.getInstance().getRadioPolicyManager();
        int currentChannel = rpm.getChannelNumber();
        short currentPan = rpm.getPanId();
        int currentPower = rpm.getOutputPower();

        System.out.println("channel " + currentChannel);
        System.out.println("PAN ID " + currentPan);
        System.out.println("power " + currentPower);

        ISleepManager sleepManager = Spot.getInstance().getSleepManager();
        System.out.println("shallow sleep " + sleepManager.getMaximumShallowSleepTime());

        runIrqLatencyTest();

        ISyncClock syncClock = Spot.getInstance().getSyncClock();

        System.out.println("sync clock: " + syncClock.getDriverName());
        
        // ISyncClock at91tcClock = new AT91TimerCounterSyncClock();
        // ISyncClock at91tcClock = new ChainedAT91TimerCounterSyncClock();
        IClockController clockController = new PIDClockController(syncClock, 10, 1000, 0, false);
        TimeServer timeServer;
        TimeClient timeClient;
        try {
            if (ourAddr == serverAddr)
                timeServer = new TimeServer();
            else
                timeClient = new TimeClient(clockController);
            
        } catch (IOException ex) {
            ex.printStackTrace();
        }

        ISwitch sw1 = EDemoBoard.getInstance().getSwitches()[EDemoBoard.SW1];
        leds[0].setRGB(100,0,0);                // set color to moderate red
        while (sw1.isOpen()) {                  // done when switch is pressed
            leds[0].setOn();                    // Blink LED
            Utils.sleep(250);                   // wait 1/4 seconds
            leds[0].setOff();
            Utils.sleep(2000);                  // wait 1 second


            // System.out.println("system: " + syncClock.currentTimeMicros());
            //System.out.println("timer : " + at91tcClock.currentTimeMicros());
        }


        notifyDestroyed();                      // cause the MIDlet to exit
    }

    protected void pauseApp() {
        // This is not currently called by the Squawk VM
    }

    /**
     * Called if the MIDlet is terminated by the system.
     * I.e. if startApp throws any exception other than MIDletStateChangeException,
     * if the isolate running the MIDlet is killed with Isolate.exit(), or
     * if VM.stopVM() is called.
     * 
     * It is not called if MIDlet.notifyDestroyed() was called.
     *
     * @param unconditional If true when this method is called, the MIDlet must
     *    cleanup and release all resources. If false the MIDlet may throw
     *    MIDletStateChangeException  to indicate it does not want to be destroyed
     *    at this time.
     */
    protected void destroyApp(boolean unconditional) throws MIDletStateChangeException {
        for (int i = 0; i < 8; i++) {
            leds[i].setOff();
        }
    }

    protected void testLong(Long l) {
        // l = new Long(100L);
    }

    protected void runIrqLatencyTest() {
     new Thread() {

            public void run() {

                IAT91_TC timer = Spot.getInstance().getAT91_TC(3);
                VM.setSystemThreadPriority(Thread.currentThread(), VM.MAX_SYS_PRIORITY);

                final double usecPerTick = 2.1368;

                int max = 0;
                int min = 0xFFFF;
                int total = 0;
                int irqs = 0;

                // hystogram
                int[] usec_bins = new int[100]; // 0 - 1000us, 10us bins
                int[] msec_bins = new int[100]; // 0 - 1000ms, 10ms bins

                while (true) {
                    timer.configure(
                            TimerCounterBits.TC_CAPT |
                            TimerCounterBits.TC_CLKS_MCK128);	// enable RC compare

                    timer.enableAndReset();

                    for (int i = 0; i < 200; ++i) {
                        timer.enableIrq(TimerCounterBits.TC_COVFS);
                        timer.waitForIrq();
                        timer.status();

                        final int count = timer.counter();
                        max = count > max ? count : max;
                        min = count < min ? count : min;
                        total += count;
                        irqs += 1;

                        final int usecs = (int)(count * usecPerTick) / 10;
                        final int msecs = usecs / 1000;

                        usec_bins[Math.min(usecs, 99)] += 1;
                        msec_bins[Math.min(msecs, 99)] += 1;
                    }
                    timer.disable();

                    double max_usecs = max * usecPerTick;
                    double min_usecs = min * usecPerTick;
                    double avg_usecs = (total * usecPerTick) / irqs;

                    System.out.println("[irq lantecy] max " + max_usecs + "(" + max + ")");
                    System.out.println("[irq lantecy] min " + min_usecs + "(" + min + ")");
                    System.out.println("[irq lantecy] avg " + avg_usecs);

                    System.out.println("[irq lantecy] histogram");
                    for(int i = 0; i < 100; ++i) {
                        System.out.println(usec_bins[i] + "," + msec_bins[i]);
                    }
                    Utils.sleep(1000);
                }
            }
        }.start();
    }
}
